/**
 * 
 */
package com.zte.claa.inficombo.csa.app.service.sapi.ffhost.mina;

import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zte.claa.inficombo.csa.app.util.EdianUtil;

/**
 * @author lyp0283000115
 *
 */
public class FFTransDevMsgDecoder implements MessageDecoder {
	// logger
	private static final Logger LOG = LoggerFactory.getLogger(FFTransDevMsgDecoder.class);
	// 字符集
	private Charset charset = null;
	// private CharsetDecoder charsetDecoder = null;

	public FFTransDevMsgDecoder(Charset charset) {
		this.charset = charset;
		if (this.charset == null) {
			this.charset = Charset.forName("UTF-8");
		}
		// this.charsetDecoder = this.charset.newDecoder();
	}

	/**
	 *检查是否能够解码
	 */
	public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
		LOG.info("Received data = ["+in.getHexDump()+"]");
		if (in.remaining() < FFTransDevMessage.getMinMsgSize()) {
			LOG.info("[1].Current data is not enough, wait new data coming...["+in.getHexDump()+"]");
			return MessageDecoderResult.NEED_DATA;
		}
		try {		
			byte[] tmpBs = new byte[24];
			in.get(tmpBs);
			// 字段长度字节
			tmpBs = new byte[2];
			in.get(tmpBs);
			int len = Short.toUnsignedInt(EdianUtil.byteToShort_LH(tmpBs, 0));
			if (in.remaining() < (len + 4)) {
				LOG.info("[2].Current data is not enough, wait new data coming...["+in.getHexDump()+"]");
				return MessageDecoderResult.NEED_DATA;
			}
		} catch (Exception e) {
			LOG.error("***[session=" + session.getId()+"]decodable error: "+e.getMessage(), e);
		}
		return MessageDecoderResult.OK;
	}

	/**
	 * 解码
	 */
	public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
		LOG.info("begin to decode[sessionid=" + session.getId() + "]...");
		try {
			FFTransDevMessage msg = new FFTransDevMessage();
			// 起始字符.
			msg.setStartB1(in.get());
			msg.setStartB2(in.get());
			// 流水号（2个字节）
			byte[] bs = new byte[2];
			in.get(bs);
			msg.setSno(Short.toUnsignedInt(EdianUtil.byteToShort_LH(bs, 0)));
			// 版本号
			msg.setMainVersion(in.get());
			msg.setUserVersion(in.get());
			// 时间标签.
			msg.setSecond(in.get());
			msg.setMinute(in.get());
			msg.setHour(in.get());
			msg.setDay(in.get());
			msg.setMonth(in.get());
			msg.setYear(in.get());
			// 源地址
			bs = new byte[6];
			in.get(bs);
			msg.setSrcAddrBytes(bs);
			// 目标地址
			bs  = new byte[6];
			in.get(bs);
			msg.setDstAddrBytes(bs);
			// datalen （两个字节）
			bs = new byte[2];
			in.get(bs);
			int dataLen = Short.toUnsignedInt(EdianUtil.byteToShort_LH(bs, 0));
			// cmd
			msg.setCmd(in.get());
			// 应用数据.
			if(dataLen > 0){
				bs = new byte[dataLen];
				in.get(bs);
				msg.setData(bs);
			} else {
				msg.setData(new byte[0]);
			}
			// 校验和
			msg.setCheckSum(in.get());
			// 结束符
			msg.setEndB1(in.get());
			msg.setEndB2(in.get());
			
			// 返回解码结果
			out.write(msg);
			LOG.info("OK: finish decoding[session=" + session.getId()+", msg: "+msg.toString());
			return MessageDecoderResult.OK;			
		} catch (Exception e) {
			LOG.error("***[session=" + session.getId()+"]decode error:"+e.getMessage(), e);
			this.processInvalidMsg(session, in);
		}
		return MessageDecoderResult.OK;
	}
	
	/**
	 * 处理掉无效消息字节流
	 * 
	 * @param session
	 * @param in
	 */
	private void processInvalidMsg(IoSession session, IoBuffer in){
		// in.getHexDump() 不会调整pos和limit等指针.
		LOG.warn("Buffer decode: data is invalid, pos="+in.position()+", limit="+in.limit()+", data="+in.getHexDump());
		int pos = in.position();
		int limit = in.limit();
		int leftSize = in.remaining();
		in.skip(leftSize);
		LOG.warn("***[session=" + session.getId()+"]skip invalid data:　pos="+pos+", limit="+limit+", leftSize="+leftSize+", left-data="+in.getHexDump());
		// 此处返回NOT_OK，MINA框架的DemuxingProtocolDecoder会将pos--limit之间的数据丢弃，此时可能会包含“跨包消息的异常丢弃”...
		// return MessageDecoderResult.NOT_OK;
		// return MessageDecoderResult.OK;
	}

	/**
	 * 
	 */
	public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {
		LOG.debug("FinishDecode for session: " + session.getId());
	}
	
}
